package cn.flying.cloud.base.common.utils.crypto;

import java.io.File;
import java.io.FileInputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 摘要工具类
 *
 * @author: admin
 * @date: 2025年01月22日 13:08
 * @version: 1.0
 */
public class DigestUtil {
    private static final Logger logger = LoggerFactory.getLogger(DigestUtil.class);

    /**
     * 将任意字符通过摘要 与 Base64 进行定长编码
     *
     * @param data      待加密字符
     * @param algorithm 信息生成摘要的算法，默认为  MD5，可选值有  SHA-1、SHA-256、MD5
     * @return 加密后字符
     */
    public static String digest(String data, String algorithm) {
        String result = "";
        try {
            algorithm = algorithm == null ? "MD5" : algorithm;
            //指定信息摘要算法提取摘要的哈希值. 哈希值字节数组
            MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
            byte[] bytes = messageDigest.digest(data.getBytes(StandardCharsets.UTF_8));
            //使用 BASE64 进行编码 如果直接 new String(bytes) 是会乱码的
            result = Base64.getEncoder().encodeToString(bytes);
        } catch (Exception e) {
            logger.error("摘要编码失败", e);
        }
        return result;
    }

    /**
     * 将任意字符通过摘要 与 Base64 进行定长编码
     *
     * @param data      待加密字符
     * @param algorithm 信息生成摘要的算法，默认为  MD5，可选值有  SHA-1、SHA-256、MD5
     * @return 加密后字符
     */
    public static String digest(byte[] data, String algorithm) {
        String result = "";
        try {
            algorithm = algorithm == null ? "MD5" : algorithm;
            //指定信息摘要算法提取摘要的哈希值. 哈希值字节数组
            MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
            //使用 BASE64 进行编码 如果直接 new String(bytes) 是会乱码的
            result = Base64.getEncoder().encodeToString(data);
        } catch (Exception e) {
            logger.error("摘要编码失败", e);
        }
        return result;
    }

    /**
     * 对文件提取摘要
     *
     * @param file      ：待提取摘要的文件
     * @param algorithm 生成摘要的算法，默认为  MD5，可选值有  SHA-1、SHA-256、MD5
     * @return
     */
    public static String digest(File file, String algorithm) {
        String result = "";
        algorithm = algorithm == null ? "MD5" : algorithm;
        //构建文件输入流，然后获取文件通道。
        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            //FileChannel 用于读取，写入，映射和操作文件的通道。
            FileChannel fileChannel = fileInputStream.getChannel();
            /**
             * map(MapMode mode,long position, long size)：将此频道文件的区域直接映射到内存中。
             * position - 映射区域要启动的文件中的位置; 必须是非负的
             * size - 要映射的区域的大小; 必须是非负数，不得大于Integer.MAX_VALUE
             */
            MappedByteBuffer byteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
            //指定信息摘要算法提取摘要的哈希值. 哈希值字节数组
            MessageDigest digest = MessageDigest.getInstance(algorithm);
            //使用指定的 ByteBuffer 更新摘要.
            digest.update(byteBuffer);
            byte[] bytes = digest.digest();
            return Base64.getEncoder().encodeToString(bytes);
        } catch (Exception e) {
            logger.error("摘要编码失败", e);
        }
        return result;
    }

//    public static void main(String[] args) {
//
//        new DigestUtils().test1();
////        new Md5EncodeUtils().test2();
//
//    }
//
//    public void test2() {
//        File file = new File("C:\\Users\\Think\\Downloads\\commons-io-2.6-bin.tar.gz");
//        String fileMd5Digest = digest(file, "SHA-256");
//        System.out.println("fileMd5Digest: " + fileMd5Digest.toLowerCase());
//    }
//
//    public void test1() {
//        String sourceMessage = "123456万里长城_&*$#.Nice";
//        //原字符：123456万里长城_&*$#.Nice
//        System.out.println("原字符：" + sourceMessage);
//
//        String md5Msg = digest(sourceMessage, "md5");
//        String sha1Msg = digest(sourceMessage, "SHA-1");
//        String sha256Msg = digest(sourceMessage, "SHA-256");
//        //md5 + base64 加密后：rIJQEL19bo+eV5p7qPLlDg==
//        System.out.println("md5 + base64 加密后：" + md5Msg);
//        //md5 + base64 加密后：UYg5qBdsuCdloFP+0CVPasziIEU=
//        System.out.println("SHA-1 + base64 加密后：" + sha1Msg);
//        //md5 + base64 加密后：dqTa6BTTvZ4zLF5WNAH5Cv660RxYMEIJlBRIGKdNXmM=
//        System.out.println("SHA-256 + base64 加密后：" + sha256Msg);
//    }
}